use std::{
    collections::{HashMap, HashSet},
    str::FromStr,
    sync::Arc,
};

use crate::generator::{
    BoolGenerator, Generator,
    number::{
        RangeF32Generator, RangeF64Generator, RangeI8Generator, RangeI16Generator,
        RangeI32Generator, RangeI64Generator, RangeU8Generator, RangeU16Generator,
        RangeU32Generator, RangeU64Generator, RangeUsizeGenerator,
    },
    text::{Ipv4Generator, Ipv6Generator, RegexTextGenerator},
};
use apikit_doc::{
    document::ApiDocument,
    ty::{
        ApiConstraitType, ApiField, ApiFields, ApiMembers, ApiTypeId, ApiTypeInfo, ApiTypeKind,
        CollectApiTypeInfo, IntoApiTypeId,
    },
};
use glass::Reflect;
use log::{error, warn};
use rand::seq::IteratorRandom;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::{Map, Number, Value};

pub type GenerateFn = fn(value: Value) -> Value;

pub fn generate<T: DeserializeOwned + Generator>(generator: Value) -> Value {
    if generator == Value::Null {
        return T::default().generate();
    }
    let generator: Result<T, serde_json::Error> = serde_json::from_value(generator);
    match generator {
        Ok(generator) => generator.generate(),
        Err(e) => {
            error!("generator deserialize fail: {e:?}");
            Value::Null
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BasicTypeConfig {
    pub id: ApiTypeId,
    pub value: Value,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct NamedFieldsMockConfig {
    pub fields: HashMap<String, Value>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct UnNamedFieldsMockConfig {
    pub fields: HashMap<usize, Value>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub enum EnumMockStrategy {
    #[default]
    Random,
    Appoint(HashSet<String>),
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct EnumMockConfig {
    pub strategy: EnumMockStrategy,
    pub named_config: HashMap<String, NamedFieldsMockConfig>,
    pub unnamed_config: HashMap<String, UnNamedFieldsMockConfig>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub enum OptionMockStrategy {
    #[default]
    Random,
    Some,
    None,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct OptionMockConfig {
    pub strategy: OptionMockStrategy,
    pub config: Option<Value>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub enum ResultMockStrategy {
    #[default]
    Random,
    Ok,
    Err,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct ResultMockConfig {
    pub strategy: ResultMockStrategy,
    pub ok_config: Option<Value>,
    pub err_config: Option<Value>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct ArrayMockConfig {
    pub min_amount: Option<usize>,
    pub max_amount: Option<usize>,
    pub config: Option<Value>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct TupleMockConfig {
    pub config: HashMap<usize, Value>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct MapMockConfig {
    pub min_amount: Option<usize>,
    pub max_amount: Option<usize>,
    pub k_config: Option<Value>,
    pub v_config: Option<Value>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct MockOptions {
    pub max_recursion: usize,
    pub serilaize: bool,
}

#[derive(Clone)]
pub struct GeneratorInfo {
    pub generate_fn: GenerateFn,
    pub generator_id: ApiTypeId,
    pub type_kind: ApiTypeKind,
}

pub trait Mocker {
    fn mock(
        &self,
        type_id: &ApiTypeId,
        config: Option<Value>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let type_info = self.get_type_info(type_id);
        let Some(type_info) = type_info else {
            return Value::Null;
        };
        *current_recursion += 1;
        let overlimit = *current_recursion >= options.max_recursion;
        if overlimit {
            warn!("mock reach recursion limit: {options:?}");
        }
        let matched_generators = self.matched_generators(type_info);
        if !matched_generators.is_empty() {
            if let Some(config) = config {
                let config: Result<BasicTypeConfig, serde_json::Error> =
                    serde_json::from_value(config);
                if let Ok(config) = config {
                    let generator_info = self.get_generator_info(&config.id);
                    if let Some(generator_info) = generator_info {
                        return (generator_info.generate_fn)(config.value);
                    }
                }
            }

            let index = rand::random_range(0..matched_generators.len());
            let generator = matched_generators.get(index);
            let Some(generator) = generator else {
                return Value::Null;
            };
            return (generator.generate_fn)(Value::Null);
        }

        match &type_info.kind {
            ApiTypeKind::NamedStruct(_) => {
                if overlimit {
                    return Value::Object(Map::default());
                }
                let ApiMembers::Fields(fields) = &type_info.members else {
                    return Value::Object(Map::default());
                };
                let config = config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_named_struct(fields, config, current_recursion, options)
            }
            ApiTypeKind::TupleStruct(_) => {
                if overlimit {
                    return Value::Array(vec![]);
                }
                let ApiMembers::Fields(fields) = &type_info.members else {
                    return Value::Array(vec![]);
                };
                let config = config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_tuple_struct(fields, config, current_recursion, options)
            }
            ApiTypeKind::Enum(_) => {
                let config = config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_enum(type_info, config, current_recursion, options)
            }
            ApiTypeKind::Option(type_id) => {
                if overlimit {
                    return Value::Null;
                }
                let config: Option<OptionMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_option(type_id, config, current_recursion, options)
            }
            ApiTypeKind::Result(ok_type_id, err_type_id) => {
                let config: Option<ResultMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_result(ok_type_id, err_type_id, config, current_recursion, options)
            }
            ApiTypeKind::Array(item_type_id, size) => {
                if overlimit {
                    return Value::Array(vec![]);
                }
                let config: Option<ArrayMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_array(
                    item_type_id,
                    Some(*size),
                    true,
                    config,
                    current_recursion,
                    options,
                )
            }
            ApiTypeKind::Tuple(items) => {
                if overlimit {
                    return Value::Array(vec![]);
                }
                let config: Option<TupleMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_tuple(items, config, current_recursion, options)
            }
            ApiTypeKind::Vec(item_type_id) => {
                if overlimit {
                    return Value::Array(vec![]);
                }
                let config: Option<ArrayMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_array(item_type_id, None, true, config, current_recursion, options)
            }
            ApiTypeKind::Set(item_type_id) => {
                if overlimit {
                    return Value::Array(vec![]);
                }
                let config: Option<ArrayMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_array(
                    item_type_id,
                    None,
                    false,
                    config,
                    current_recursion,
                    options,
                )
            }
            ApiTypeKind::Map(k_type_id, v_type_id) => {
                if overlimit {
                    return Value::Object(Map::default());
                }
                let config: Option<MapMockConfig> =
                    config.map(|f| serde_json::from_value(f).unwrap_or_default());
                self.mock_map(k_type_id, v_type_id, config, current_recursion, options)
            }
            _ => Value::Null,
        }
    }

    fn mock_map(
        &self,
        k_type_id: &ApiTypeId,
        v_type_id: &ApiTypeId,
        config: Option<MapMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let mut map = Map::default();
        let config = config.unwrap_or_default();
        let min_amount = config.min_amount.unwrap_or(0);
        let max_amount = config.max_amount.unwrap_or(10);
        let size = rand::random_range(min_amount..=max_amount);
        let k_config = config.k_config;
        let v_config = config.v_config;
        for _ in 0..size {
            let key = self.mock(k_type_id, k_config.clone(), current_recursion, options);
            if let Value::String(k) = key {
                let v = self.mock(v_type_id, v_config.clone(), current_recursion, options);
                map.insert(k, v);
            }
        }
        Value::Object(map)
    }

    fn mock_array(
        &self,
        type_id: &ApiTypeId,
        size: Option<usize>,
        repeatable: bool,
        config: Option<ArrayMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let config = config.unwrap_or_default();
        let min_amount = config.min_amount.unwrap_or(0);
        let max_amount = config.max_amount.unwrap_or(10);
        let size = size.unwrap_or(rand::random_range(min_amount..=max_amount));
        let config = config.config;
        if repeatable {
            let mut arr = vec![];
            for _ in 0..size {
                let value = self.mock(type_id, config.clone(), current_recursion, options);
                arr.push(value);
            }
            Value::Array(arr)
        } else {
            let mut arr = HashSet::new();
            for _ in 0..size {
                let value = self.mock(type_id, config.clone(), current_recursion, options);
                arr.insert(value);
            }
            Value::Array(Vec::from_iter(arr))
        }
    }

    fn mock_tuple(
        &self,
        type_ids: &[ApiTypeId],
        config: Option<TupleMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let mut arr = vec![];
        let mut config = config.unwrap_or_default();
        for (index, type_id) in type_ids.iter().enumerate() {
            let config = config.config.remove(&index);
            let value = self.mock(type_id, config, current_recursion, options);
            arr.push(value);
        }
        Value::Array(arr)
    }

    fn mock_option(
        &self,
        type_id: &ApiTypeId,
        config: Option<OptionMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        match config {
            Some(config) => {
                let strategy = config.strategy;
                match strategy {
                    OptionMockStrategy::Random => {
                        let value = rand::random_bool(1.0 / 3.0);
                        if value {
                            let config = config.config;
                            self.mock(type_id, config, current_recursion, options)
                        } else {
                            Value::Null
                        }
                    }
                    OptionMockStrategy::Some => {
                        let config = config.config;
                        self.mock(type_id, config, current_recursion, options)
                    }
                    OptionMockStrategy::None => Value::Null,
                }
            }
            None => self.mock(type_id, None, current_recursion, options),
        }
    }

    fn mock_result(
        &self,
        ok_type_id: &ApiTypeId,
        err_type_id: &ApiTypeId,
        config: Option<ResultMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let config = config.unwrap_or_default();
        let strategy = config.strategy;
        match strategy {
            ResultMockStrategy::Random => {
                let value = rand::random_bool(1.0 / 3.0);
                if value {
                    let config = config.ok_config;
                    self.mock(ok_type_id, config, current_recursion, options)
                } else {
                    let config = config.err_config;
                    self.mock(err_type_id, config, current_recursion, options)
                }
            }
            ResultMockStrategy::Ok => {
                let config = config.ok_config;
                self.mock(ok_type_id, config, current_recursion, options)
            }
            ResultMockStrategy::Err => {
                let config = config.err_config;
                self.mock(err_type_id, config, current_recursion, options)
            }
        }
    }

    fn mock_named_struct(
        &self,
        fields: &ApiFields,
        config: Option<NamedFieldsMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let mut map = Map::default();
        let mut config = config.unwrap_or_default();
        for field in &fields.fields {
            let key = if options.serilaize {
                field.serde.serialize.as_ref().or(field.ident.as_ref())
            } else {
                field.serde.deserialize.as_ref().or(field.ident.as_ref())
            };
            let Some(key) = key else {
                continue;
            };
            let config = config.fields.remove(key);
            if config.is_none() {
                let field_value = self.mock_field_value(field, current_recursion, options);
                if let Some(field_value) = field_value {
                    map.insert(key.clone(), field_value);
                    continue;
                }
            }
            let value = self.mock(&field.type_id, config, current_recursion, options);
            map.insert(key.clone(), value);
        }
        Value::Object(map)
    }

    fn mock_field_value(
        &self,
        field: &ApiField,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Option<Value> {
        let type_info = self.get_type_info(&field.type_id);
        let type_info = type_info?;
        let type_info = if let ApiTypeKind::Option(type_id) = &type_info.kind {
            let value = rand::random_bool(1.0 / 3.0);
            if value {
                return Some(Value::Null);
            }
            self.get_type_info(type_id)?
        } else {
            type_info
        };

        let mut regex = None;
        let mut min_amount = None;
        let mut max_amount = None;

        for constraint in &field.constraints {
            match constraint {
                ApiConstraitType::Length(min, max, _) => {
                    min_amount = Some(*min);
                    max_amount = Some(*max);
                }
                ApiConstraitType::Range(min, max, _) => {
                    let is_f32 = matches!(type_info.kind, ApiTypeKind::F32);
                    let is_f64 = matches!(type_info.kind, ApiTypeKind::F64);
                    if is_f32 || is_f64 {
                        let min: Result<f64, _> = min.parse();
                        let Ok(min) = min else {
                            continue;
                        };
                        let max: Result<f64, _> = max.parse();
                        let Ok(max) = max else {
                            continue;
                        };
                        let float_generator = RangeF64Generator {
                            min: Some(min),
                            max: Some(max),
                        };
                        return Some(float_generator.generate());
                    }
                    let min: Result<i64, _> = min.parse();
                    let Ok(min) = min else {
                        continue;
                    };
                    let max: Result<i64, _> = max.parse();
                    let Ok(max) = max else {
                        continue;
                    };
                    let int_generator = RangeI64Generator {
                        min: Some(min),
                        max: Some(max),
                    };
                    return Some(int_generator.generate());
                }
                ApiConstraitType::Regex(r, _) => {
                    regex = Some(r.clone());
                }
                ApiConstraitType::Enumer(enum_type_id, _) => {
                    let enum_type_info = self.get_type_info(enum_type_id);
                    if let Some(enum_type_info) = enum_type_info {
                        let members = &enum_type_info.members;
                        if let ApiMembers::Variants(variants) = members {
                            let index = rand::random_range(0..variants.len());
                            let variant = variants.get(index);
                            if let Some(variant) = variant {
                                let is_str = matches!(type_info.kind, ApiTypeKind::String);
                                if is_str {
                                    return Some(Value::String(variant.ident.clone()));
                                } else {
                                    return Some(Value::from(variant.value.unwrap_or_default()));
                                }
                            }
                        }
                    }
                }
                ApiConstraitType::SelfValidate(_) => continue,
                ApiConstraitType::Constant(value, _) => {
                    let is_string = matches!(type_info.kind, ApiTypeKind::String);
                    if is_string {
                        return Some(Value::String(value.clone()));
                    }
                    let is_bool = matches!(type_info.kind, ApiTypeKind::Bool);
                    if is_bool {
                        return Some(Value::Bool(value.parse().unwrap_or_default()));
                    }
                    let number = Number::from_str(value);
                    if let Ok(number) = number {
                        return Some(Value::Number(number));
                    }
                }
            }
        }
        if let ApiTypeKind::Vec(type_id) = &type_info.kind {
            return Some(self.mock_array(
                type_id,
                None,
                true,
                Some(ArrayMockConfig {
                    min_amount,
                    max_amount,
                    config: None,
                }),
                current_recursion,
                options,
            ));
        }
        if let ApiTypeKind::Set(type_id) = &type_info.kind {
            return Some(self.mock_array(
                type_id,
                None,
                false,
                Some(ArrayMockConfig {
                    min_amount,
                    max_amount,
                    config: None,
                }),
                current_recursion,
                options,
            ));
        }
        if let ApiTypeKind::String = &type_info.kind {
            if min_amount.is_some() && max_amount.is_some() && regex.is_none() {
                let min_amount = min_amount.unwrap_or(0);
                let max_amount = max_amount.unwrap_or(0);
                regex = Some(format!(
                    r"[_a-zA-Z\u4e00-\u9fa5]{{{min_amount}, {max_amount}}}"
                ));
            }
            let regex_generator = RegexTextGenerator {
                regex,
                max_repetition: None,
                unicode: None,
            };
            return Some(regex_generator.generate());
        }

        None
    }

    fn mock_tuple_struct(
        &self,
        fields: &ApiFields,
        config: Option<UnNamedFieldsMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let mut arr = vec![];
        let mut config = config.unwrap_or_default();
        if fields.fields.len() == 1 {
            let field = fields.fields.first();
            let Some(field) = field else {
                return Value::Array(arr);
            };
            let config = config.fields.remove(&0);
            if config.is_none() {
                let field_value = self.mock_field_value(field, current_recursion, options);
                if let Some(field_value) = field_value {
                    return field_value;
                }
            }
            return self.mock(&field.type_id, config, current_recursion, options);
        }

        for (index, field) in fields.fields.iter().enumerate() {
            let config = config.fields.remove(&index);
            if config.is_none() {
                let field_value = self.mock_field_value(field, current_recursion, options);
                if let Some(field_value) = field_value {
                    arr.push(field_value);
                }
            }

            let value = self.mock(&field.type_id, config, current_recursion, options);
            arr.push(value);
        }
        Value::Array(arr)
    }

    fn mock_enum(
        &self,
        type_info: &ApiTypeInfo,
        config: Option<EnumMockConfig>,
        current_recursion: &mut usize,
        options: &MockOptions,
    ) -> Value {
        let ApiMembers::Variants(variants) = &type_info.members else {
            return Value::Null;
        };
        let mut config = config.unwrap_or_default();
        let selected = match config.strategy {
            EnumMockStrategy::Random => {
                let index = rand::random_range(0..variants.len());
                variants.get(index)
            }
            EnumMockStrategy::Appoint(hash_set) => {
                let mut rng = rand::rng();
                let ident = hash_set.iter().choose(&mut rng);
                match ident {
                    Some(ident) => {
                        let mut selected = None;
                        for variant in variants {
                            if variant.ident.eq(ident) {
                                selected = Some(variant)
                            }
                        }
                        selected
                    }
                    None => None,
                }
            }
        };
        let Some(selected) = selected else {
            return Value::Null;
        };
        let fields = &selected.fields;
        if fields.fields.is_empty() {
            return Value::String(selected.ident.clone());
        }
        let mut map = Map::default();
        let value = if selected.fields.named {
            let config = config
                .named_config
                .remove(&selected.ident)
                .unwrap_or_default();
            self.mock_named_struct(fields, Some(config), current_recursion, options)
        } else {
            let config = config
                .unnamed_config
                .remove(&selected.ident)
                .unwrap_or_default();
            self.mock_tuple_struct(fields, Some(config), current_recursion, options)
        };
        map.insert(selected.ident.clone(), value);
        Value::Object(map)
    }

    fn matched_generators(&self, type_info: &ApiTypeInfo) -> Vec<&GeneratorInfo>;

    fn get_generator_info(&self, generator_id: &ApiTypeId) -> Option<&GeneratorInfo>;

    fn get_type_info(&self, type_id: &ApiTypeId) -> Option<&ApiTypeInfo>;
}

pub struct DefalutMocker {
    pub document: Arc<ApiDocument>,
    pub generator_types: HashMap<String, ApiTypeInfo>,
    generator_infos: HashMap<String, GeneratorInfo>,
}

impl DefalutMocker {
    pub fn new(mock_types: Arc<ApiDocument>) -> Self {
        let mut generator_infos = HashMap::new();
        let mut generator_types = HashMap::new();

        let type_info = BoolGenerator::type_info();
        let type_id = type_info.type_id.into_api_type_id();
        type_info.collect(&mut generator_types);
        generator_infos.insert(
            type_id.clone(),
            GeneratorInfo {
                generate_fn: generate::<BoolGenerator>,
                generator_id: type_id,
                type_kind: ApiTypeKind::Bool,
            },
        );

        macro_rules! registe_range_number {
            ($ident: ident, $ty: ident) => {
                let type_info = $ident::type_info();
                let type_id = type_info.type_id.into_api_type_id();
                type_info.collect(&mut generator_types);
                generator_infos.insert(
                    type_id.clone(),
                    GeneratorInfo {
                        generate_fn: generate::<$ident>,
                        generator_id: type_id,
                        type_kind: ApiTypeKind::$ty,
                    },
                );
            };
        }
        registe_range_number!(RangeI8Generator, I8);
        registe_range_number!(RangeI16Generator, I16);
        registe_range_number!(RangeI32Generator, I32);
        registe_range_number!(RangeI64Generator, I64);
        registe_range_number!(RangeU8Generator, U8);
        registe_range_number!(RangeU16Generator, U16);
        registe_range_number!(RangeU32Generator, U32);
        registe_range_number!(RangeU64Generator, U64);
        registe_range_number!(RangeUsizeGenerator, Usize);
        registe_range_number!(RangeF32Generator, F32);
        registe_range_number!(RangeF64Generator, F64);

        let type_info = RegexTextGenerator::type_info();
        let type_id = type_info.type_id.into_api_type_id();
        type_info.collect(&mut generator_types);
        generator_infos.insert(
            type_id.clone(),
            GeneratorInfo {
                generate_fn: generate::<RegexTextGenerator>,
                generator_id: type_id,
                type_kind: ApiTypeKind::String,
            },
        );

        let type_info = Ipv4Generator::type_info();
        let type_id = type_info.type_id.into_api_type_id();
        type_info.collect(&mut generator_types);
        generator_infos.insert(
            type_id.clone(),
            GeneratorInfo {
                generate_fn: generate::<Ipv4Generator>,
                generator_id: type_id,
                type_kind: ApiTypeKind::String,
            },
        );

        let type_info = Ipv6Generator::type_info();
        let type_id = type_info.type_id.into_api_type_id();
        type_info.collect(&mut generator_types);
        generator_infos.insert(
            type_id.clone(),
            GeneratorInfo {
                generate_fn: generate::<Ipv6Generator>,
                generator_id: type_id,
                type_kind: ApiTypeKind::String,
            },
        );

        Self {
            document: mock_types,
            generator_types,
            generator_infos,
        }
    }
}

impl Mocker for DefalutMocker {
    fn get_type_info(&self, type_id: &ApiTypeId) -> Option<&ApiTypeInfo> {
        self.document
            .types
            .get(type_id)
            .or(self.generator_types.get(type_id))
    }

    fn matched_generators(&self, type_info: &ApiTypeInfo) -> Vec<&GeneratorInfo> {
        let mut result = vec![];
        for v in self.generator_infos.values() {
            if v.type_kind.eq(&type_info.kind) {
                result.push(v);
            }
        }
        result
    }

    fn get_generator_info(&self, generator_id: &ApiTypeId) -> Option<&GeneratorInfo> {
        self.generator_infos.get(generator_id)
    }
}
